<template>
	<el-popover :hide-after="0" :placement="props.placement" :visible="state.inputFocus" :width="state.selectorWidth">

		<div class="icon-selector">
			<transition name="el-zoom-in-center">
				<div class="icon-selector-box">
					<div class="selector-header">
						<div class="selector-title">{{ props.title ? props.title : '请选择图标' }}</div>
						<div class="selector-tab">
							<span :class="state.iconType === 'ele' ? 'active' : ''" title="Element Plus 图标"
							      @click="onChangeTab('ele')">ele</span>
							<span :class="state.iconType === 'awe' ? 'active' : ''" title="Font Awesome 图标"
							      @click="onChangeTab('awe')">awe</span>
							<span :class="state.iconType === 'ali' ? 'active' : ''" title="阿里 Iconfont 图标"
							      @click="onChangeTab('ali')">ali</span>
							<span :class="state.iconType === 'local' ? 'active' : ''"
							      title="本地图标:src/assets/icons/svg/cus中的.svg" @click="onChangeTab('local')">local</span>
						</div>
					</div>
					<div class="selector-body">
						<el-scrollbar>
							<div v-if="renderFontIconNames.length > 0">
								<div v-for="(iconName, key) in renderFontIconNames" :key="key" :title="iconName"
								     class="icon-selector-item" @click="onIcon(iconName)">
									<icon :name="iconName" size="18px"/>
								</div>
							</div>
						</el-scrollbar>
					</div>
				</div>
			</transition>
		</div>

		<template #reference>
			<el-input ref="selectorInputRef" v-model="state.inputValue" :class="'size-' + props.size" :disabled="disabled"
			          :size="props.size" placeholder="搜索图标" @blur="onInputBlur" @focus="onInputFocus">
				<template #prepend>
					<div class="icon-prepend">
						<Icon :key="'icon' + state.iconKey" :name="state.prependIcon ? state.prependIcon : state.defaultModelValue"
						      size="18"/>
						<div v-if="props.showIconName" class="name">{{
								state.prependIcon ? state.prependIcon : state.defaultModelValue
							}}
						</div>
					</div>
				</template>
				<template #append>
					<Icon name="el-icon-RefreshRight" size="18" style="cursor: pointer" @click="onInputRefresh"/>
				</template>
			</el-input>
		</template>
	</el-popover>

</template>

<script lang="ts" setup>
import {computed, nextTick, onMounted, reactive, ref, watch} from 'vue'
import type {InputInstance, Placement} from 'element-plus'
import {getAwesomeIconfontNames, getElementPlusIconfontNames, getIconfontNames, getLocalIconfontNames} from '@/utils/iconUtil'
import {useWebConfigStore} from '@/stores/modules/webConfig.store'
import Icon from '@/components/icon.vue'

type IconType = 'ele' | 'awe' | 'ali' | 'local'

interface Props {
	size?: 'default' | 'small' | 'large'
	disabled?: boolean
	title?: string
	type?: IconType
	placement?: Placement
	modelValue?: string
	showIconName?: boolean
}

const props = withDefaults(defineProps<Props>(), {
	size: 'default',
	disabled: false,
	title: '',
	type: 'ele',
	placement: 'bottom',
	modelValue: '',
	showIconName: false
})

const emits = defineEmits<{
	(e: 'update:modelValue', value: string): void
	(e: 'change', value: string): void
}>()

const webConfigStore = useWebConfigStore()
const selectorInputRef = ref<InputInstance>()
const state: {
	iconType: IconType
	selectorWidth: number
	inputFocus: boolean
	fontIconNames: string[]
	inputValue: string
	prependIcon: string
	defaultModelValue: string
	iconKey: number
} = reactive({
	iconType: props.type,
	selectorWidth: 0,
	inputFocus: false,
	fontIconNames: [],
	inputValue: '',
	prependIcon: props.modelValue,
	defaultModelValue: props.modelValue || webConfigStore.layout.menuDefaultIcon,
	iconKey: 0 // 给icon标签准备个key，以随时使用 h 函数重新生成元素
})

const onInputFocus = () => {
	state.inputFocus = true
}
const onInputBlur = () => {
	state.inputFocus = false
}
const onInputRefresh = () => {
	state.iconKey++
	state.prependIcon = state.defaultModelValue
	state.inputValue = ''
	emits('update:modelValue', state.defaultModelValue)
	emits('change', state.defaultModelValue)
}
const onChangeTab = (name: IconType) => {
	state.iconType = name
	state.fontIconNames = []
	switch (name) {
		case 'ele':
			getElementPlusIconfontNames().then((res: string[]) => {
				state.fontIconNames = res
			})
			break
		case 'awe':
			getAwesomeIconfontNames().then((res: string[]) => {
				state.fontIconNames = res.map((name) => `fa ${name}`)
			})
			break
		case 'ali':
			getIconfontNames().then((res: string[]) => {
				state.fontIconNames = res.map((name) => `iconfont ${name}`)
			})
			break
		case 'local':
			getLocalIconfontNames().then((res: string[]) => {
				state.fontIconNames = res
			})
			break
		default:
			break
	}
}
const onIcon = (icon: string) => {
	state.iconKey++
	state.prependIcon = icon
	state.inputValue = ''
	emits('update:modelValue', icon)
	emits('change', icon)
	selectorInputRef.value?.blur()
}

const renderFontIconNames = computed(() => {
	if (!state.inputValue) {
		return state.fontIconNames
	}
	let inputValue = state.inputValue.trim().toLowerCase()
	return state.fontIconNames.filter((icon: string) => icon.toLowerCase().indexOf(inputValue) !== -1)
})

// 获取 input 的宽度
const getInputWidth = () => {
	nextTick(() => {
		state.selectorWidth = selectorInputRef.value?.$el.offsetWidth < 260 ? 260 : selectorInputRef.value?.$el.offsetWidth
	})
}

watch(() => props.modelValue, () => {
			state.iconKey++
			if (props.modelValue != state.prependIcon) {
				state.defaultModelValue = props.modelValue
			}
			if (!props.modelValue) {
				state.defaultModelValue = webConfigStore.layout.menuDefaultIcon
			}
			state.prependIcon = props.modelValue
		}
)

onMounted(() => {
	getInputWidth()
	getElementPlusIconfontNames().then((res: string[]) => {
		state.fontIconNames = res
	})
})
</script>

<style lang="scss" scoped>
.size-small {
	height: 24px;
}

.size-large {
	height: 40px;
}

.size-default {
	height: 32px;
}

.icon-prepend {
	align-items: center;
	display: flex;
	justify-content: center;

	.name {
		padding-left: 5px;
	}
}

.selector-header {
	align-items: center;
	display: flex;
	margin-bottom: 12px;
}

.selector-tab {
	margin-left: auto;

	span {
		cursor: pointer;
		padding: 0 5px;
		user-select: none;

		&.active,
		&:hover {
			color: var(--el-color-primary);
			text-decoration: underline;
		}
	}
}

.selector-body {
	height: 250px;
}

.icon-selector-item {
	border: 1px solid var(--cus-border-color);
	border-radius: var(--el-border-radius-base);
	cursor: pointer;
	display: inline-block;
	margin: 3px;
	padding: 10px 10px 6px 10px;

	.icon {
		height: 18px;
		width: 18px;
	}

	&:hover {
		border: 1px solid var(--el-color-primary);
	}
}

:deep(.el-input-group__prepend) {
	padding: 0 10px;
}

:deep(.el-input-group__append) {
	padding: 0 10px;
}
</style>
